package org.sun.sunshine.io.nio.channel;

import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@Slf4j
public class NioSocketChannelServerDemo {
    private Charset charset = Charset.forName("UTF-8");
    private String BASE_PATH="/Users/yushengjun/IdeaProjects/sunshine/producer/src/main/java/org/sun/sunshine/io/nio/channel/";
    /**
     * 内部类，服务器端保存的客户端对象，对应一个客户端文件
     */
    static class Client {
        //文件名称
        String fileName;
        //长度
        long fileLength;
        //开始传输的时间
        long startTime;
        //客户端的地址
        InetSocketAddress remoteAddress;
        //输出的文件通道
        FileChannel outChannel;
    }

    private ByteBuffer buffer = ByteBuffer.allocate(1024);
    private Map<SocketChannel, Client> clients = new HashMap<>();

    public void receiveFile() {
        try(Selector selector = Selector.open();
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        ) {
            serverSocketChannel.bind(new InetSocketAddress("127.0.0.1",8080));
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            while(selector.select()>0){
                Iterator<SelectionKey>  keys = selector.selectedKeys().iterator();
                while(keys.hasNext()){
                    SelectionKey key = keys.next();
                    if(key.isAcceptable()){
                        ServerSocketChannel server
                                = (ServerSocketChannel) key.channel();
                        //客户端链接
                        SocketChannel channel =  server.accept();
                        if(channel==null){
                            continue;
                        }
                        channel.configureBlocking(false);
                        channel.register(selector, SelectionKey.OP_READ);

                        //
                        Client client = new Client();
                        client.remoteAddress = (InetSocketAddress) channel.getRemoteAddress();
                        clients.put(channel,client);
                    }else if(key.isReadable()){
                        SocketChannel channel = (SocketChannel) key.channel();
                        Client client = clients.get(channel);
                        //切换到可写模式
                        buffer.clear();

                        //开始读数据
                        int num=0;
                        //这里的read 和对面的write 对应？
                        while((num=channel.read(buffer))>0){
                            buffer.flip();
                            if(client.fileName==null){
                                //todo 按位截取

                                byte[] temp=new byte[buffer.limit()];
                                buffer.get(temp,0,buffer.limit());
                                ByteBuffer tempBuff=ByteBuffer.wrap(temp);

                                client.fileName = charset.decode(tempBuff).toString();
                                String filepath = BASE_PATH+"o"+client.fileName;
                                System.out.println(filepath);
                                Path path= Paths.get(BASE_PATH+"o"+client.fileName);
                                client.outChannel = FileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
                            }else if(client.fileLength==0){
                                client.fileLength=buffer.getLong();
                            }else{
                                //读文件
                                client.outChannel.write(buffer);
                            }
                            buffer.clear();
                        }
                        //当前处理结束
                        key.cancel();
                        // 读取数量-1，表示客户端传输结束标志到了
                        if (num == -1) {
                            client.outChannel.close();
                            key.cancel();
                            log.info("文件接收成功,File Name：{}" , client.fileName);
                            log.info("size: {}" , client.fileLength);
                        }
                    }
                    keys.remove();
                }

            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }


    public static void main(String[] args) {
        NioSocketChannelServerDemo demo = new NioSocketChannelServerDemo();
        demo.receiveFile();
    }

}
